<!DOCTYPE html>
<html lang="en">
  <head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
 
<link rel="stylesheet" href="../assets/css/style.css"/> 
<!-- Copyright 1998-2021 by Northwoods Software Corporation. -->    <title> GoJS and Angular -- Northwoods Software </title>
    <link rel="stylesheet" href="../assets/css/prism.css"  />
  </head>
  <script>
    
    window.diagrams = [];
    window.goCode = function(pre, w, h, parentid, animation) {
      window.diagrams.push([pre, w, h, parentid, animation]);
    }
  </script>
  <body>
  <nav id="navTop" class="w-full z-30 top-0 text-white bg-nwoods-primary">
    <div class="w-full container max-w-screen-lg mx-auto flex flex-wrap sm:flex-nowrap items-center justify-between mt-0 py-2">
      <div class="md:pl-4">
        <a class="text-white hover:text-white no-underline hover:no-underline
        font-bold text-2xl lg:text-4xl rounded-lg hover:bg-nwoods-secondary " href="../">
          <h1 class="mb-0 p-1 ">GoJS</h1>
        </a>
      </div>
      <button id="topnavButton" class="rounded-lg sm:hidden focus:outline-none focus:ring" aria-label="Navigation">
        <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
          <path id="topnavOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
          <path id="topnavClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
        </svg>
      </button>
      <div id="topnavList" class="hidden lg:text-base sm:block items-center w-auto mt-0 text-white p-0 z-20">
        <ul class="list-reset list-none font-semibold flex justify-end flex-wrap sm:flex-nowrap items-center px-0 pb-0">
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../learn/">Learn</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../samples/">Samples</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../intro/">Intro</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../api/">API</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/products/register.html">Register</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../download.html">Download</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://forum.nwoods.com/c/gojs/11">Forum</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/contact.html"
           target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/sales/index.html"
           target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a></li>
        </ul>
      </div>
    </div>
    <hr class="border-b border-gray-600 opacity-50 my-0 py-0" />
  </nav>
    
    <div class="md:flex flex-col md:flex-row md:min-h-screen w-full max-w-screen-xl mx-auto">
      
    <div id="navSide" class="flex flex-col w-full md:w-40 lg:w-48 text-gray-700 bg-white flex-shrink-0">
      <div class="flex-shrink-0 px-8 py-4">
        <button id="navButton" class="rounded-lg md:hidden focus:outline-none focus:ring" aria-label="Navigation">
          <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
            <path id="navOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
            <path id="navClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
          </svg>
        </button>
      </div>
      <nav id="navList" class="min-h-screen hidden md:block sidebar-nav flex-grow px-1 lg:px-4 pb-4 md:pb-0 md:overflow-y-auto break-words">
  <a href="index.html">Basics</a>
  <a href="buildingObjects.html">Building Parts</a>
  <a href="usingModels.html">Using Models</a>
  <a href="dataBinding.html">Data Binding</a>
  <a href="react.html">GoJS with React</a>
  <a href="angular.html">GoJS with Angular</a>
  <a href="textBlocks.html">TextBlocks</a>
  <a href="shapes.html">Shapes</a>
  <a href="pictures.html">Pictures</a>
  <a href="panels.html">Panels</a>
  <a href="tablePanels.html">Table Panels</a>
  <a href="brush.html">Brushes</a>
  <a href="sizing.html">Sizing Objects</a>
  <a href="itemArrays.html">Item Arrays</a>
  <a href="changedEvents.html">Changed Events</a>
  <a href="transactions.html">Transactions</a>
  <a href="viewport.html">Coordinates</a>
  <a href="initialView.html">Initial View</a>
  <a href="collections.html">Collections</a>
  <a href="links.html">Links</a>
  <a href="linkLabels.html">Link Labels</a>
  <a href="connectionPoints.html">Link Points</a>
  <a href="ports.html">Ports</a>
  <a href="nodes.html">Nodes</a>
  <a href="debugging.html">Debugging</a>
  <a href="layouts.html">Layouts</a>
  <a href="trees.html">Trees</a>
  <a href="subtrees.html">SubTrees</a>
  <a href="groups.html">Groups</a>
  <a href="subgraphs.html">SubGraphs</a>
  <a href="sizedGroups.html">Sized Groups</a>
  <a href="selection.html">Selection</a>
  <a href="highlighting.html">Highlighting</a>
  <a href="animation.html">Animation</a>
  <a href="toolTips.html">ToolTips</a>
  <a href="contextmenus.html">Context Menus</a>
  <a href="events.html">Diagram Events</a>
  <a href="tools.html">Tools</a>
  <a href="commands.html">Commands</a>
  <a href="permissions.html">Permissions</a>
  <a href="validation.html">Validation</a>
  <a href="HTMLInteraction.html">HTML Interaction</a>
  <a href="layers.html">Layers &amp; Z-ordering</a>
  <a href="palette.html">Palette</a>
  <a href="overview.html">Overview</a>
  <a href="resizing.html">Resizing Diagrams</a>
  <a href="replacingDeleting.html">Replacing and Deleting</a>
  <a href="buttons.html">Buttons</a>
  <a href="templateMaps.html">Template Maps</a>
  <a href="legends.html">Legends and Titles</a>
  <a href="extensions.html">Extensions</a>
  <a href="geometry.html">Geometry Strings</a>
  <a href="grids.html">Grid Patterns</a>
  <a href="graduatedPanels.html">Graduated Panels</a>
  <a href="makingImages.html">Diagram Images</a>
  <a href="makingSVG.html">Diagram SVG</a>
  <a href="printing.html">Printing</a>
  <a href="serverSideImages.html">Server-side Images</a>
  <a href="nodeScript.html">GoJS in Node.js</a>
  <a href="testing.html">Testing</a>
  <a href="storage.html">Storage</a>
  <a href="performance.html">Performance</a>
  <a href="source.html">Building from Source</a>
  <a href="platforms.html">Platforms</a>
  <a href="deployment.html">Deployment</a>
      </nav>
    </div>      
      <div class="pt-4 px-2 md:px-0 lg:px-4 pb-16 w-full overflow-hidden">
<div id="container" class="container-fluid">
    <div id="content">

        <h1>Using GoJS with Angular</h1>
        <p class="box" style="background-color: lightgoldenrodyellow;">
            Examples of most of the topics discussed on this page can be found in the <a href="https://github.com/NorthwoodsSoftware/gojs-angular-basic"
                                                                                         target="_blank">gojs-angular-basic</a>
            project,
            which serves as a simple starter project.
        </p>

        <p>
            If you are new to GoJS, it may be helpful to first visit the <a href="../learn/index.html" target="_blank">
                Getting
                Started Tutorial
            </a>.
        </p>

        <p>
            The easiest way to get a component set up for a GoJS Diagram is to use the <a href="#TODO" target="_blank">gojs-angular</a>
            package,
            which exports Angular Components for GoJS Diagrams, Palettes, and Overviews.
            More information about the package, including the various props it takes, can be found on the
            <a href="https://npmjs.com/gojs-react" target="_blank">NPM</a> page. Examples here will be using a <a>GraphLinksModel</a>,
            but any model can be used.
        </p>

        <p>
            <b>Note:</b> This page is assumes use of <code>gojs-angular</code> version 2.0+. <a href="#MigratingTo2.0">Click here</a> for a discussion
            on upgrading to version 2.0.
        </p>

        <h2 id="GeneralInformation">General Information</h2>
        <h3 id="Installation">Installation</h3>
        <p>
            To use the published components, make sure you install GoJS and gojs-angular: <code>npm install gojs gojs-angular</code>.
        </p>

        <h3 id="AboutComponentStyling">About Component Styling</h3>
        <p>
            Whether you are using a Diagram, Palette, or Overview <code>gojs-angular</code> component, you will
            probably
            want to style them.
            First, you'll need to style a CSS class for the div of your GoJS Diagram / Palette / Overview such as:
        </p>
        <pre class="lang-css"> <code>
/* app.component.css */
.myDiagramDiv {
  background: whitesmoke;
  width: 800px;
  height: 300px;
  border: 1px solid black;
}
           </code> </pre>

        <p>
            To style the GoJS Diagram / Palette / Overivew div, which will reside in the <code>gojs-angular</code>
            component(s) you are using, make sure you set the <code>@Component</code> decorator's <code>encapsulation</code>
            propety to either
            <code>ViewEncapsulation.None</code> or <code>ViewEncapsulation.ShadowDown</code>. Without this, your
            styling will not effect
            the
            component divs.
            Read more about Angular view encapsulation <a href="https://angular.io/api/core/ViewEncapsulation">here</a>.
        </p>
        <p>
            Your <code>@Component</code> decorator for the component holding the your GoJS / Angular Component(s)
            should
            look something
            like:
        </p>
        <pre class="lang-ts"> <code>
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  encapsulation: ViewEncapsulation.None
})
</code></pre>
        <p>
            <strong>Note:</strong> You may alternatively use the default <code>ViewEncapsulation.Emulated</code>
            value, if you assign additional CSS modifiers :host and ::ng-deep to your class selector. Be warned,
            however, ng-deep is technically deprecated, so this is not best practice.
        </p>

        <h2 id="DataSyncService">The DataSyncService</h2>

        <p>
            The <code>gojs-angular</code> package comes with an Angular <a href="https://angular.io/tutorial/toh-pt4">service</a>
            called DataSyncService, used to
            easily merge changes (a <a href="https://gojs.net/latest/api/symbols/IncrementalData.html">go.IncrementalData</a>
            instance) with an Array of Node or Link Data, or a <a href="https://gojs.net/latest/api/symbols/Model.html#modelData">
                modelData
            </a> object.
        </p>
        <p>This service has three static functions: </p>
        <ul>
            <li>
                <code>syncNodeData(changes, array)</code> - Merges any node data changes in a go.IncrementalData
                object
                with a given array of node data, then returns the new array
            </li>
            <li>
                <code>syncLinkData(changes, array)</code> - Merges any link data changes in a go.IncrementalData
                object
                with a given array of link data, then returns the new array. <strong>Note</strong>: Ensure you set
                the <a href="https://gojs.net/latest/api/symbols/GraphLinksModel.html#linkKeyProperty">linkKeyProperty</a>
                if you are using GraphLinksModel, so data merging is possible.
            </li>
            <li>
                <code>syncModelData(changes, object)</code> - Merges any modelData changes in a go.IncrementalData
                object
                with a given modelData object, then returns the new object
            </li>
        </ul>

        <p>
            These functions should allow you to keep your data synced up as needed, without needing to write lots
            of
            code.
        </p>

        <h3 id="ListeningForModelChanges">Listening for Model Changes</h3>
        <p>
            It is common to listen for data changes in a Diagram or Palette, then do
            something with
            those changes on an application-level (such as syncing those changes with app-level data). That's why,
            for both the DiagramComponent
            and
            PaletteComponent, there is a <code>modelChange</code> <code>@Input</code> property function. This is a
            prime example of where the DataSyncService can be used.
        </p>

        <p>
            As of <code>gojs-angular</code> 2.0, Array / object <code>@Input</code>
            properties are assumed to be immutable. As such, when updating these properties, new Arrays / objects
            must be generated -- one cannot simply mutate an element of the Array or object.
            Please see the <a href="https://github.com/NorthwoodsSoftware/gojs-angular-basic">gojs-angular-basic</a>
            project for examples of both maintaining state immutability and usage of the DataSyncService.
        </p>

        <p>
            <strong>Note:</strong> The <a href="https://gojs.net/latest/api/symbols/UndoManager.html">UndoManager</a>
            should always be
            enabled to allow for transactions to take place, but its
            <a href="https://gojs.net/latest/api/symbols/UndoManager.html#maxHistoryLength">maxHistoryLength</a>
            can be set to 0 to prevent undo and redo.
        </p>

        <br>
        <h2 id="UsingDiagramComponent">The Diagram and Palette Components</h2>
        <p>The Diagram and Palette Components accept a similar set of <code>@Input</code> properties.</p>
        <p>
            Diagram Component accepts:
            <ul>
                <li>
                    <code>initDiagram</code> - A function that must return a GoJS Diagram. You may define your
                    Diagram's
                    Node
                    and Link templates here.
                </li>
                <li><code>divClassName</code> - A class name for your Diagram div</li>
                <li><code>nodeDataArray</code> - An array containing data objects for your nodes </li>
                <li><code>linkDataArray</code> - An array containing data objects for your links. Optional. </li>
                <li>
                    <code>modelData</code> - A data object,
                    containing your diagram's <a href="https://gojs.net/latest/api/symbols/Model.html#modelData">model.modelData</a>.
                    Optional.
                <li>
                    <code>skipsDiagramUpdate</code> - A boolean flag, specifying whether the component should skip
                    updating,
                    often set when updating state from a GoJS model change.
                </li>
                <li>
                    <code>modelChange</code> - A function, which accepts a <a href="">go.IncrementalData</a>
                    object.
                    This function will fire when your Diagram's model changes, allowing you to decide what to do
                    with those
                    changes. A common practice is to sync your app-level data to reflect the changes in the diagram
                    model,
                    which
                    is made simple using the DataSyncService <code>gojs-angular</code> ships with.
                </li>
            </ul>
        </p>

        <p>
            The Palette Component accepts:
        </p>
        <ul>
            <li>
                <code>initPalette</code> - A function that must return a GoJS Palette. You may define your
                Palette's Node
                and Link templates here.
            </li>
            <li><code>divClassName</code> - A class name for the div your Palette div</li>
            <li><code>nodeDataArray</code> - An array containing data objects for your nodes </li>
            <li><code>linkDataArray</code> - An array containing data objects for your links. Optional. </li>
            <li>
                <code>modelData</code> - A data object,
                containing your palette's <a href="https://gojs.net/latest/api/symbols/Model.html#modelData">model.modelData</a>.
                Optional.
        </ul>
        <p>
            Because GoJS Palettes are read-only by default, there is no <code>modelChange</code> property in PaletteComponent. Since there won't be user-driven changes to a Palette's model,
            changes to node/link/model data should be achieved by immutably altering the analogous above @Input properties.
        </p>

        <h2>Sample Diagram / Palette Component Usage</h2>
        <p>
            Here is an example of how one might set up their Diagram / Palette component properties
            <pre class="lang-ts"> <code>
// Big object that holds app-level state data
// As of gojs-angular 2.0, immutability is required of state for change detection
public state = {
  // Diagram state props
  diagramNodeData: [
    { id: 'Alpha', text: "Alpha", color: 'lightblue' },
    { id: 'Beta', text: "Beta", color: 'orange' }
  ],
  diagramLinkData: [
    { key: -1, from: 'Alpha', to: 'Beta' }
  ],
  diagramModelData: { prop: 'value' },
  skipsDiagramUpdate: false,

  // Palette state props
  paletteNodeData: [
    { key: 'PaletteNode1', color: 'firebrick' },
    { key: 'PaletteNode2', color: 'blueviolet' }
  ]
}; // end state object

public diagramDivClassName: string = 'myDiagramDiv';
public paletteDivClassName = 'myPaletteDiv';

// initialize diagram / templates
public initDiagram(): go.Diagram {
  const $ = go.GraphObject.make;
  const dia = $(go.Diagram, {
    'undoManager.isEnabled': true,
    model: $(go.GraphLinksModel,
      {
        nodeKeyProperty: 'id',
        linkKeyProperty: 'key' // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
      }
    )
  });

  // define the Node template
  dia.nodeTemplate =
    $(go.Node, 'Auto',
        $(go.Shape, 'RoundedRectangle', { stroke: null },
          new go.Binding('fill', 'color')
        ),
        $(go.TextBlock, { margin: 8, editable: true },
          new go.Binding('text').makeTwoWay())
      );
  return dia;
}

/**
 * Handle GoJS model changes, which output an object of data changes via Mode.toIncrementalData.
 * This method should iterate over thoe changes and update state to keep in sync with the FoJS model.
 * This can be done with any preferred state management method, as long as immutability is preserved.
 */
public diagramModelChange = function(changes: go.IncrementalData) {
  console.log(changes);
  // see gojs-angular-basic for an example model changed handler that preserves immutability
  // when setting state, be sure to set skipsDiagramUpdate: true since GoJS already has this update
};

public initPalette(): go.Palette {
  const $ = go.GraphObject.make;
  const palette = $(go.Palette);

  // define the Node template
  palette.nodeTemplate =
    $(go.Node, 'Auto',
      $(go.Shape, 'RoundedRectangle', { stroke: null },
        new go.Binding('fill', 'color')
      ),
      $(go.TextBlock, { margin: 8 },
        new go.Binding('text', 'key'))
    );

  palette.model = $(go.GraphLinksModel,
    {
      linkKeyProperty: 'key'  // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
    });

  return palette;
}
</code></pre>

        <p>
            Once you've defined your <code>@Input</code> properties for your components, pass these properties
            to your DiagramComponent and PaletteComponent in your template, like so:
        </p>

        <pre class="lang-html"> <code>
&lt;gojs-diagram
  [initDiagram]='initDiagram'
  [nodeDataArray]='state.diagramNodeData'
  [linkDataArray]='state.diagramLinkData'
  [modelData]='state.diagramModelData'
  [skipsDiagramUpdate]='state.skipsDiagramUpdate'
  (modelChange)='diagramModelChange($event)'
  [divClassName]='diagramDivClassName'&gt;
&lt;/gojs-diagram&gt;

&lt;gojs-palette
  [initPalette]='initPalette'
  [nodeDataArray]='state.paletteNodeData'
  [divClassName]='paletteDivClassName'&gt;
&lt;/gojs-palette&gt;
</code></pre>

  <p>
    You will now have a GoJS Diagram and Palette working in your Angular application. Again, for a full
    example of a <code>gojs-angular</code> application, see <a href="https://github.com/NorthwoodsSoftware/gojs-angular-basic">gojs-angular-basic</a>.
  </p>

  <h4>A Note on Diagram Reinitialization</h4>
  <p>
    Occasionally you may want to treat a model update as if you were loading a completely new model.
    But initialization is only done in your <code>initDiagram</code> function,
    within the <code>DiagramComponent</code>'s <code>ngAfterViewInit</code> lifecycle hook, and only once.
    A regular model update is not treated as an initialization, so none of the <code>initial...</code> properties
    of your Diagram will apply.
  </p>
  <p>
    To address this problem, <code>DiagramComponent</code> exposes a <code>clear</code> method.
    When called, it clears its diagram of all nodes, links, and model data, and
    prepares the next state update to be treated as a diagram initialization.
    That will result in an initial layout and perform initial diagram content alignment and scaling.
    Note that <code>initDiagram</code> is not called again.
  </p>
  <p>
    Here is a small sample of how one might trigger diagram reinitilization using the <code>clear</code> method with <code>gojs-angular</code> 2.0.
  </p>
<pre class="lang-ts"><code>
public reinitModel() {
    this.myDiagramComponent.clear();
    this.state = produce(this.state, draft => {
        draft.skipsDiagramUpdate = false;
        draft.diagramNodeData = [{ id: "Alpha", text: "Zorro", color: "red" }];
        draft.diagramLinkData = [];
    });
}
</code></pre>

        <br>
        <h2 id="UsingOverviewComponent">Using the Overview Component</h2>
        <p>
            The Overview Component accepts the following Angular <code>@Input()</code> properties.
        </p>
        <ul>
            <li><code>initOverview</code> - A function that must return a GoJS Overview.</li>
            <li><code>divClassName</code> - A class name for your Overview div</li>
            <li><code>observedDiagram</code> - The GoJS Diagram this Overview observes</li>
        </ul>

        <p>
            Define these properties in the component that will hold your Overview Component, like:
        </p>

        <pre class="lang-ts"> <code>
public oDivClassName = 'myOverviewDiv';
public initOverview(): go.Overview {
  const $ = go.GraphObject.make;
  const overview = $(go.Overview);
  return overview;
}
public observedDiagram = null;</code></pre>

        <p>
            Then pass these properties to your Overview Component in your template, like:
        </p>

        <pre class="lang-html"> <code>
&lt;gojs-overview
  [initOverview]='initOverview'
  [divClassName]='oDivClassName'
  [observedDiagram]='observedDiagram'&gt;
&lt;/gojs-overview&gt; </code></pre>

        <p>
            But, we're not done yet. <code>observedDiagram</code> is null, so the Overview won't observe
            anything.
            To assign your Overview a Diagram to observe, you will have to reassign the <code>observedDiagram</code>
            property after initialization. To do so,
            reassign the bound <code>observedDiagram</code> property in your component holding your Overview
            Component in the <code>ngAfterViewInit</code> lifecycle hook.
        </p>
        <p>
            <strong>Note</strong>: To avoid a <code>ExpressionChangedAfterItHasBeenCheckedError</code>, you
            must
            inform
            Angular
            to then detect changes.
            This can be done with the <a href="https://angular.io/api/core/ChangeDetectorRef#detectchanges">ChangeDetectorRef.detectChanges()</a>
            method. You can inject a ChangeDetectorRef instance
            into your wrapper Component constructor, and use that after you alter <code>observedDiagram</code>
            to
            call
            detectChanges(). Like so:
        </p>

        <pre class="lang-ts"> <code>
constructor(private cdr: ChangeDetectorRef) { }

public ngAfterViewInit() {
  if (this.observedDiagram) return;
  // in this snippet, this.myDiagramComponent is a reference to a GoJS/Angular Diagram Component
  // that has a valid GoJS Diagram
  this.observedDiagram = this.myDiagramComponent.diagram;

  // IMPORTANT: without this, Angular will throw ExpressionChangedAfterItHasBeenCheckedError (dev mode only)
  this.cdr.detectChanges();
}
       </code></pre>

        <p>
            Now, after initialization, your Overview should display appropriately.
        </p>

        <br>
        <h2 id="UpdatingPropertiesBasedOnAppState">Updating Properties Based on App State</h2>
        <p>
            You may have some app-level properties you want to affect the behavior / appearance of your
            Diagram,
            Palette,
            or Overview. You could subclass their respective components and add <code>@Input</code> bindings
            with
            specific
            setter methods, or, more simply, you can have an <code>ngOnChanges</code> function in your
            app-level
            component
            that updates various Diagram / Palette / Component properties based on your app state.
        </p>

        <p>
            For example, say you have an app-level property called <code>showGrid</code>. When <code>showGrid</code>
            is
            true, your Diagram's grid should be visible -- when false, it should be invisible. In your
            AppComponent, you
            could do something like:
        </p>

        <pre class="lang-ts"> <code>

// myDiagramComponent is a reference to your DiagramComponent
@ViewChild('myDiagram', { static: true }) public myDiagramComponent: DiagramComponent;

public ngOnChanges () {
  // whenever showGrid changes, update the diagram.grid.visible in the child DiagramComponent
  if (this.myDiagramComponent && this.myDiagramComponent.diagram instanceof go.Diagram) {
    this.myDiagramComponent.diagram.grid.visible = this.showGrid;
  }
}
      </code></pre>

        <h2 id="MigratingTo2.0">Migrating to 2.0</h2>
        <p>
            This page assumes use of <code>gojs-angular</code> version 2.0, which
            requires
            immutable state, unlike version 1.0. It is recommended to use the 2.0 version. If you have a
            <code>gojs-angular</code> project using version 1.x and want to upgrade, reference this section for tips on migrating to version 2.
        </p>
        <h3>Should I Upgrade?</h3>
        <p>
            In general, yes.
        </p>
        <p>
            If you have very simple node and link data, using the latest 1.x version might be okay. But new features and quality of life changes
            will be published on the
            2.x branch moving forward.
        </p>
        <p>
            Version 2.0 handles complex nested data much better than the previous version, due to its focus on immutable data. Additionally, it is a bit
            smaller in file size.
        </p>
        <p>
            One may wish to hold off on upgrading if they have lots of operations mutating their <code>@Input</code> properties, and they do not want to take the
            time to rewrite those operations immutably. However, the guide below details one way one could do this. Our <code>gojs-angular-basic</code> sample also
            has demonstrations of immutably updating <code>@Input</code> properties to make such a rewrite easier.
        </p>
        <h3>Upgrade gojs-angular Version </h3>
        <p>
            Update your <code>package.json</code> to require <code>gojs-angular</code> version 2.0 or greater,
            then run <code>npm install</code>
        </p>
        <p>
            It is also recommended to upgrade to the lastest version of <code>gojs</code>.
        </p>
        <h3>Immutability</h3>
        <p>
            The biggest change with 2.0 is you must enforce immutability of <code>@Input</code>
            properties to your Diagram and Palette components.
        </p>
        <p>
            So, for instance, whenever an entry of <code>diagramNodeData</code>
            is updated, removed, or changed, you will need to generate a whole new Array for <code>DiagramComponent.diagramNodeData</code>. This can be done in
            many different ways with many different packages. A popular choice is <a href="https://github.com/immerjs/immer">immer</a>, which exposes a <code>produce</code> function
            that allows one to immutability manipulate their data on a <code>draft</code> variable. We will use that function here for demonstration purposes.
        </p>

        <h4>The Version 1.0 Way</h4>
        <p>
            In <code>gojs-angular</code> version 1, if you wanted to add some node data to your <code>diagramNodeData</code> <code>@Input</code> property,
            you could do so by simply adding to the <code>diagramNodeData</code>, mutating it. Such as:
        </p>

        <pre class="lang-ts"><code>
public addNode = function(nodeData: go.ObjectData) {
  // sync changes with GoJS model
  this.skipsDiagramUpdate = false;
  this.diagramNodeData.push(nodeData);
};
          </code></pre>

        <h4>The Version 2.0 Way</h4>
        <p>
            In <code>gojs-angular</code> version 2, that same <code>addNode</code> function must be changed so the <code>diagramNodeData</code>
            property is updated immutably (that is, replaced with an entirely new Array). Here is an example of
            doing that with immer's <code>produce</code> function.
        </p>

        <pre class="lang-ts"><code>
public addNode = function(nodeData: go.ObjectData) {
  this.state = produce(this.state, draft => {
    var nodedata = { id: "Zeta", text: "Zorro", color: "red" };
    draft.skipsDiagramUpdate = false;
    draft.diagramNodeData.push(nodedata);
  });
}
          </code></pre>

        <p>
            Notice we are also using a massive <code>state</code> object to hold <code>gojs-angular</code> component properties. This makes these kinds
            of immutable operations (especially if you are using immer, or a package like it) straightforward (see how we were able to update both <code>skipsDiagramUpdate</code>
            and <code>diagramNodeData</code> on the same <code>draft</code> variable).
        </p>

        <p>
            To see more samples of enforcing immutability with <code>gojs-angular</code>, see <a href="https://github.com/NorthwoodsSoftware/gojs-angular-basic">gojs-angular-basic</a>,
            particularly the <code>modelChange</code> property of the Diagram Component.
        </p>
        <h3>Additional Considerations</h3>
        <p>
            Additionally, PaletteComponent no longer supports <code>skipsPaletteUpdate</code> or <code>modelChange</code> properties. As GoJS Palettes are read-only by default, their models should not
            be changing based on user input. Instead, if you need to update their node/link/model data, update their <code>@Input</code> properties (immutably, of course).
        </p>


    </div>
</div>
      </div>
    </div>
  
  <div class="bg-nwoods-primary">
    <section class="max-w-screen-lg text-white container mx-auto py-2 px-12">
      <p id="version" class="leading-none mb-2 my-4">GoJS</p>
    </section>
  </div><footer class="bg-nwoods-primary text-white">
  <div class="container max-w-screen-lg mx-auto  px-8">
    <div class="w-full py-6">

        <div class="max-w-screen-lg xl:max-w-screen-xl mx-auto px-4 sm:px-6 md:px-8">
          <ul class="text-sm font-medium pb-14 sm:pb-20 grid grid-cols-1 sm:grid-cols-3 gap-y-10">
            <li class="list-none row-span-2">
              <h2 class="text-base font-semibold tracking-wide">GoJS</h2>
              <ul class="list-none space-y-4 md:space-y-1 px-0">
                <li>
                  <a href="../samples/index.html">Samples</a>
                </li>
                <li>
                  <a href="../learn/index.html">Learn</a>
                </li>
                <li>
                  <a href="../intro/index.html">Intro</a>
                </li>
                <li>
                  <a href="../api/index.html">API</a>
                </li>
                <li>
                  <a href="../changelog.html">Changelog</a>
                </li>
                <li>
                  <a href="https://github.com/NorthwoodsSoftware/GoJS">GitHub</a>
                </li>
              </ul>
            </li>
            <li class="list-none row-span-2">
              <h2 class="text-base font-semibold tracking-wide">Support</h2>
              <ul class="list-none space-y-4 md:space-y-1 px-0">
                <li>
                  <a href="https://www.nwoods.com/contact.html"
                  target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a>
                </li>
                <li>
                  <a href="https://forum.nwoods.com/c/gojs">Forum</a>
                </li>
                <li>
                  <a href="https://www.nwoods.com/app/activate.aspx?sku=gojs">Activate</a>
                </li>
                <li>
                  <a href="https://www.nwoods.com/sales/index.html"
                  target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a>
                </li>
                <li>
                  <a href="https://www.youtube.com/channel/UC9We8EoX596-6XFjJDtZIDg">Videos</a>
                </li>
              </ul>
            </li>
            <li class="list-none row-span-2">
              <h2 class="text-base font-semibold tracking-wide">Company</h2>
              <ul class="list-none space-y-4 md:space-y-1 px-0">
                <li>
                  <a href="https://www.nwoods.com">Northwoods</a>
                </li>
                <li>
                  <a href="https://www.nwoods.com/about.html">About Us</a>
                </li>
                <li>
                  <a href="https://www.nwoods.com/contact.html">Contact Us</a>
                </li>
                <li>
                  <a href="https://twitter.com/northwoodsgo">Twitter</a>
                </li>

              </ul>
            </li>
          </ul>


      <p class="text-sm text-gray-100 md:mb-6">
        Copyright 1998-2021 <a class="text-white" href="https://www.nwoods.com">Northwoods Software</a>
      </p>
    </div>
  </div>
</footer>  </body>

<script async src="https://www.googletagmanager.com/gtag/js?id=UA-1506307-5"></script> 
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date()); gtag('config', 'UA-1506307-5');
  var getOutboundLink = function(url, label) {
    gtag('event', 'click', {
      'event_category': 'outbound',
      'event_label': label,
      'transport_type': 'beacon'
    });
  }

  // topnav
  var topButton = document.getElementById("topnavButton");
  var topnavList = document.getElementById("topnavList");
  topButton.addEventListener("click", function() {
    this.classList.toggle("active");
    topnavList.classList.toggle("hidden");
    document.getElementById("topnavOpen").classList.toggle("hidden");
    document.getElementById("topnavClosed").classList.toggle("hidden");
  });
</script>
  <script src="../assets/js/prism.js"></script>
  <script src="../release/go.js"></script>
  <script src="../assets/js/goDoc.js"></script>
  <script>
    document.addEventListener("DOMContentLoaded", function() {
      if (window.go) document.getElementById('version').textContent = "GoJS version " + go.version;
      if (window.goDoc) window.goDoc();
      var d = window.diagrams;
      for (var i = 0; i < d.length; i++) {
        var dargs = d[i];
        goCodeExecute(dargs[0], dargs[1], dargs[2], dargs[3], dargs[4]);
      }
      if (window.extra) window.extra();
    });
  </script>
</html>
